from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.exc import IntegrityError, DatabaseError
from sqlalchemy.orm import backref
import logging
from flask_migrate import Migrate

app = Flask(__name__)


# mysql所在的主机名
HOSTNAME = "localhost"
# post监听的端口号，默认3306
PORT = 3306
# 连接MYSQL的用户名
USERNAME = "root"
# 密码
PASSWORD = "201614"
# 数据库名称
DATABASE = "flask"

app.config['SQLALCHEMY_DATABASE_URI'] = f"mysql://{USERNAME}:{PASSWORD}@{HOSTNAME}/{DATABASE}?charset=utf8mb4"
# 需要在app中做一些配置，设置号连接数据库的信息
# 使用sql连接创建db对象
# sqlAlchemy会自动读取app.config中的信息
db = SQLAlchemy(app)

#创建一个对象
migrate = Migrate(app, db)

#ORM模型映射成表的三步曲
#1、flask db init :将项目初始化成一个（类似合并的）仓库，只需要执行一次
#2、flask db migrate:识别ORM模型的改变，生成迁移脚本
#3、flask db upgrade:运行迁移脚本，同步到数据库中
# 定义模型类
class User(db.Model):
    __tablename__ = 'user'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    # varchar类型,nullable=False字段不能为空
    username = db.Column(db.String(100), nullable=False)
    password = db.Column(db.String(100), nullable=False)


class Article(db.Model):
    __tablename__ = 'article'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    title = db.Column(db.String(200), nullable=False)
    content = db.Column(db.Text, nullable=False)
    # 添加作者的外键
    author_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    # 以后通过user访问所有文章通过articles来访问
    # backref:会自动的给User模型添加articles的属性，用来获取文章列表
    author = db.relationship("User", backref=backref("article",))


# 创建数据库表（将模型类定义放在前面确保正确解析关系）
with app.app_context():
    try:
        db.create_all()
        logging.info('数据库表创建成功')
    except Exception as e:
        logging.error(f'数据库表创建失败: {str(e)}')


@app.route('/')
def hello_world():
    return 'Hello World!'


# 数据库的增删改查

# 增加
@app.route("/user/add")
def add_user():
    try:
        # 创建ORM对象
        user = User(username="法外狂徒", password="111111")
        # 将ORM对象添加到db.session
        db.session.add(user)
        # 将db.session中改变同步到数据库
        db.session.commit()
        return '用户创建成功'
    except Exception as e:
        return f'用户创建失败，错误原因: {str(e)}'


# 查询
@app.route("/user/query")
def query_user():
    try:
        # get查找：根据主键查找,查一条
        user = User.query.get(1)
        if user:
            print(f"{user.id}:{user.username}--{user.password}")
        else:
            print('未找到主键为1的用户')
        # filter_by查找
        # Query对象，循环切片,类似数组
        users = User.query.filter_by(username="法外狂徒")
        print(type(users))
        for user in users:
            print(user.username)
        return "数据查找成功"
    except Exception as e:
        return f'数据查找失败，错误原因: {str(e)}'


# 修改
@app.route("/user/update")
def update_user():
    try:
        user = User.query.filter_by(username="法外狂徒").first()
        if user:
            user.password = "222222"
            db.session.commit()
            return "数据修改成功"
        else:
            return "未找到指定用户，无法修改"
    except Exception as e:
        return f'数据修改失败，错误原因: {str(e)}'


# 删除
@app.route("/user/delete")
def delete_user():
    try:
        # 查找
        user = User.query.get(1)
        if user:
            # 从db.session中删除
            db.session.delete(user)
            # 将db.session中同步到数据库中
            db.session.commit()
            return "删除成功"
        else:
            return "未找到主键为1的用户，无法删除"
    except Exception as e:
        return f'删除失败，错误原因: {str(e)}'


@app.route("/article/add")
def add_article():
    try:
        # 先确保存在id为2的用户
        user = User.query.get(2)
        if not user:
            return "未找到id为2的用户，请先创建用户"
        article1 = Article(title="Flask学习大概", content="Flaskxxxxx")
        article1.author = user
        db.session.add(article1)

        article2 = Article(title="Django学习大概", content="Djiango最全学校大概")
        article2.author = user
        db.session.add(article2)

        # 同步session中的数据到数据库中
        db.session.commit()
        return "文章添加成功"
    except IntegrityError as e:
        # 捕获外键约束等完整性错误
        logging.error(f'文章添加失败，完整性错误原因: {str(e)}')
        return f'文章添加失败，完整性错误原因: {str(e)}'
    except DatabaseError as e:
        # 捕获其他数据库错误
        logging.error(f'文章添加失败，数据库错误原因: {str(e)}')
        return f'文章添加失败，数据库错误原因: {str(e)}'
    except Exception as e:
        logging.error(f'文章添加失败，其他错误原因: {str(e)}')
        return f'文章添加失败，其他错误原因: {str(e)}'

@app.route("/article/query")
def query_article():
    user = User.query.get(1)
    for article in user.articles:
        print(article.title)
    return "文章查找成功"


if __name__ == '__main__':
    app.run()
